home *** CD-ROM | disk | FTP | other *** search
/ Amiga Collections: Various / DevDisk 65 (1989)(DevWare PD).zip / DevDisk 65 (1989)(DevWare PD).adf / scales / scales.doc < prev    next >
Text File  |  1990-08-07  |  16KB  |  362 lines

  1. Article 182 of net.micro.amiga:
  2. Relay-Version: version B 2.10.3 4.3bsd-beta 6/6/85; site unisoft.UUCP
  3. Posting-Version: version B 2.10.3 4.3bsd-beta 6/6/85; site well.UUCP
  4. Path: unisoft!lll-lcc!lll-crg!well!crunch
  5. From: crunch@well.UUCP (John Draper)
  6. Newsgroups: net.micro.amiga
  7. Subject: Sound Tutorial by Steven A. Bennett from BIX
  8. Message-ID: <467@well.UUCP>
  9. Date: 11 Jan 86 11:23:49 GMT
  10. Date-Received: 15 Jan 86 01:54:09 GMT
  11. Reply-To: crunch@well.UUCP (John Draper)
  12. Organization: Whole Earth 'Lectronic Link, Sausalito, CA
  13. Lines: 345
  14.  
  15. A Discussion of Simple Audio Generation on the Amiga
  16. = ========== == ====== ===== ========== == === =====
  17. by Steven A. Bennett
  18.  
  19. (permission is given to freely distribute this discussion and
  20. its associated source file, SCALES.C, as long as due credit is given)
  21.  
  22.  
  23. Introduction
  24. ------------
  25.  
  26.   Audio generation on the Amiga is not the easiest of tasks, but once
  27. one has the basic knowledge involved, it becomes no more than a matter
  28. of writing a good set of interface routines.  The Amiga can generate
  29. four channel sound through use of four DMA-driven Digital to Analog
  30. converters supplied on one of the custom chips. (Portia, I believe.)
  31. These channels can be used to generate music, speech, and sound effects
  32. with little processor overhead, in most cases.
  33.  
  34.   In this discussion I will focus mainly on simple tone generation
  35. using several channels.  Also, I have uploaded a C source file called
  36. SCALES.C to the Listings conference here on BIX, and will be referencing
  37. sectons of code in it during the discussion.  It is suggested that you
  38. download this file as an example of the interface described below.
  39.  
  40.   One further note -- My knowledge of the Audio device is based on the
  41. small section of the 1.0 ROM Manual which my dealer graciously allowed
  42. me to copy.  Thus, I may turn out to be incorrect on some of the non-Audio
  43. related areas of this discussion.  Since these are few, however, I feel able
  44. to upload this with little worry.
  45.  
  46.  
  47. The Audio Device
  48. --- ----- ------
  49.  
  50.   In the back of the ROM Kernal Manual is a description of the subroutines
  51. available in the Audio Device.  Most of the information, while perhaps
  52. useful for some complicated tasks, is unnecessary for purposes of this
  53. discussion.  The routines which are needed here are listed below:
  54.  
  55.                BeginIO()      - Begin an audio IO task
  56.                   CMD_WRITE      - Set waveform and begin audio output
  57.                   ADCMD_PERVOL   - Change period and volume
  58.                   ADCMD_FINISH   - Finish the current CMD_WRITE
  59.                OpenDevice()   - Open the audio device
  60.                WaitIO()       - Wait for the CMD_WRITE to finish
  61.  
  62. The commands listed under BeginIO() are all that are needed for simple
  63. Audio output.  Required for all of these commands is the control structure,
  64. struct IOAudio.  It is defined in devices/audio.h.
  65.  
  66.  
  67. Preparing the Driver
  68. --------- --- ------
  69.  
  70.   In order to use the Driver, one needs an IOAudio structure.  This should
  71. be public, and all unused fields zeroed out, hence we will allocate it
  72. using AllocMem():
  73.  
  74.       struct IOAudio *ioa;
  75.  
  76.       ioa = (struct IOAudio *)AllocMem(sizeof(*ioa) * NBR_IOA_STRUCTS,
  77.          MEMF_PUBLIC | MEMF_CLEAR);
  78.  
  79.   NBR_IOA_STRUCTS is the total number of IOAudio structures used by this
  80. program.  Since most programs will need more than one, we can allocate them
  81. all at once.  As always, when performing an allocation, the return ought to
  82. be checked for an error.
  83.  
  84.   Now we must open the Audio Device.  One of the items necessary for this
  85. process is a ReplyPort.  Later on, we will need several more.  (NOTE - this
  86. area is the shakiest one in this program, as I have determined the use of
  87. CreatePort from other programs and lots of guesswork)
  88.  
  89.       ioa->ioa_Request.io_Message.mn_ReplyPort =
  90.          CreatePort("Audio one", 0);
  91.  
  92.   After we have the ReplyPort, we have to set the other variables for the
  93. OpenDevice.  Here, we wish to allocate the channels (which can also be done
  94. later, using ADCMD_ALLOCATE, in which case we don't even need the ReplyPort,
  95. but it is far easier to do it here.) which will be used for output.  For
  96. this process, we need an allocation maps.  This is an array of bytes, each
  97. of which contains a bit map for the channels to be requested.  The four
  98. channels are represented by the lowest four bits in each byte.  Thus, if
  99. we wanted a map which would allocate any combination of two channels, our
  100. map might look like this:
  101.  
  102.       UBYTE aMap[] = { 0x03, 0x05, 0x09, 0x06, 0x0A, 0x0C };
  103.  
  104. which is all the combinations of two bits in the lowest four.  But for this
  105. example we simply want all four, so our map looks like this:
  106.  
  107.       UBYTE aMap[] = { 0x0f };
  108.  
  109. Now we can open the Audio Device:
  110.  
  111.       /* ln_Pri is the priority of the allocation request.
  112.        * if channels are in use, and ln_Pri is higher than the
  113.        * priority of the channel already in use, it will steal
  114.        * the channel(s) if it can't otherwise allocate them
  115.        * legally.  See ADCMD_ALLOCATE for more information on this.
  116.        */
  117.       ioa->ioa_Request.io_Message.mn_Node.ln_Pri = 10;
  118.       ioa->ioa_Data = aMap;
  119.       ioa->ioa_Length = sizeof(aMap);
  120.       error = OpenDevice(AUDIONAME, 0, ioa, 0);
  121.  
  122. If there was no error, then ioa->ioa_Request.io_Unit will be a bitmap
  123. of the successfully allocated channels.  When allocating less than four
  124. channels, one might need to look at this value to see exactly which
  125. channels it is legal to use.  An observant C programmer might notice that
  126. io_Unit is a pointer (as does the C compiler, itself).  Nevertheless, it
  127. is actually used as a bitmap, and warnings generated by the compiler on
  128. this point should be ignored.
  129.  
  130.   Now, given the opened device, one must initialize the rest of the IOAudio
  131. structures to be used by the program.  Since structure assignment in indeed
  132. implemented in the Lattice compiler (and probably the Aztec, but I can't be
  133. certain), this is easily accomplished.  The reason we must set each struct
  134. equal to the IOAudio struct returned by the OpenDevice is to copy the
  135. Device code and allocation code to the new structure.  If this is not done,
  136. then any command using the uninitialized structure will fail.
  137.  
  138.       finishioa = &ioa[1];  /* Remember the AllocMem()? */
  139.       *finishioa = *ioa;
  140.  
  141.   One absolutely must have one IOAudio structure per voice which will be
  142. playing simultaneously.  This is because the CMD_WRITE command is
  143. asyncronous, and once it has been started, the IOAudio structure is
  144. supposed to be left untouched.  For purposes of quick change, I am using
  145. two structures per voice.  All of these structures must have their own
  146. ReplyPorts, as well.
  147.  
  148.   One also needs at least one IOAudio structure for the synchronous
  149. commands ADCMD_PERVOL and ADCMD_FINISH.  I am using seperate structures
  150. for these two, again for speed.
  151.  
  152.   To see an example of initialization of these structures, examine
  153. the routine InitIOA() in SCALES.C.
  154.  
  155.  
  156. Generating a tone
  157. ---------- - ----
  158.  
  159.   In order to generate a tone, one needs several things.  A waveform array,
  160. usually in a length which is a power of two.  A period, which is calculated
  161. from the frequency of the tone and the length of the waveform array.  A
  162. volume and a duration.  And an initialized IOAudio structure.
  163.  
  164.   First, we'll determine the period.  This must be an integer between
  165. 127 and 65535, although best results occur between 127 and 500, due to
  166. the anti-aliasing filter.  (At 500, the sampling rate is only about
  167. 7150 times per second, and that is getting slow.  I could even conceive
  168. of an overtone being produced if one gets much higher.)  The period is
  169. taken from the formula:
  170.  
  171.             P = C/(WF)
  172.  
  173. where P is the period, C is the clock rate (in this case, 3579545), W is
  174. the length of the waveform array, and F is the frequency in hz.  Thus for
  175. a middle A (440 hz) with, say, a 32 byte long waveform array, the period
  176. would be:
  177.  
  178.             P = 3579545 / (32 * 440)
  179.               = 3579545 / 14080
  180.               = 254.229
  181.  
  182. Since we require an integer, this would become 254.  For those of you who
  183. haven't yet burned your ABASIC manuals, there is a table of period values
  184. on page R-138.  For the sample program, we are using period values between
  185. 428 and 226, so that our octaves start with C.  This has the advantage of
  186. lowering frequency error to about .22%, but the disadvantage of being
  187. unable to hit the highest notes.  If one can accept a frequency error of
  188. up to .39%, then the range of 240 to 127 could be used.  (For those of
  189. you wondering what those percentages come out to, its about a twentieth
  190. of a step for the former, and a tenth of a step for the latter.)
  191.  
  192. But how can we change octaves?  By doubling or halving the length of the
  193. waveform array.  So now we turn to waveforms.
  194.  
  195. A waveform array describes one cycle of a tone.  It can be simple (ie.,
  196. BYTE wfarray[2] = {127, -127}; which is a square wave) or it can be
  197. complex, involving complex transformations using harmonics.  In our
  198. sample program, we use a simple sawtooth wave, which is simply a ramp
  199. from the lowest value to the highest, then suddenly dropping to the lowest
  200. and beginning again.  The length of the waveform array determines the
  201. octave.  Since middle A (fourth octave) uses a waveform array length of
  202. 32, we can get the following size table for the various octaves:
  203.  
  204.                Octave 0 (lowest) = 512
  205.                         Octave 1 = 256
  206.                         Octave 2 = 128
  207.                         Octave 3 = 64
  208.                         Octave 4 = 32
  209.                         Octave 5 = 16
  210.                         Octave 6 = 8
  211.                         Octave 7 = 4
  212.                         Octave 8 = 2
  213.                         Octave 9 = 1    (this is impossible)
  214.  
  215. Because a sawtooth is a naturally rough wave, Octave 0 would sound pretty
  216. badly, therefore we will not use it for now.  Octave 9 is impossible for
  217. the period range we have chosen, although some of that octave could be
  218. played if we used the lower period range mentioned earlier.  It is
  219. impossible because we need at a minimum 2 samples to make a waveform.
  220. Octave 8 is currently ignored for this program because the expansion
  221. algorithm used would not produce an acceptable 2 byte waveform.
  222.  
  223.   Therefore, we create a basic, 256 byte, sawtooth wave.  The routine
  224. setwave() in SCALES.C performs this function well.  It is better
  225. if the wave can begin and end at the zero point, allowing for less chance
  226. of click when a note is changed.  A flag (ADIOF_SYNCCYCLE) can be used with
  227. the ADCMD_FINISH command to end the CMD_WRITE in progress at the end of the
  228. currently playing cycle to aid in this, but is unnecessary for our example.
  229.  
  230.   We must then expand that waveform to several waveforms of decreasing
  231. length, as set in the table of lengths above.  This is accomplished with
  232. the routine xpandwave().  The routine makewaves() will allocate memory for
  233. the wave and call both.  And here we come to an important point.
  234.  
  235.   The waveform array MUST be in chip memory!  Either it can be kept there
  236. at all times, or copied there just before use.  Do NOT assume that your
  237. program will reside in chip memory and ignore this requirement, for sooner
  238. or later you will be burnt!  Furthermore, I will make an educated guess that
  239. the waveform array should not be modified while in use.  I suspect that the
  240. CMD_WRITE command simply sets registers in the chip (at least, I hope that
  241. is what it does!) and that modifying the waveform while in use may cause
  242. unusual results.
  243.  
  244.   Finally, now that we have our period and our waveforms, we can make a
  245. tone.  To do this we need to set several entries in a currently unused
  246. IOAudio structure:
  247.  
  248.       freeioa->ioa_Request.io_Command = CMD_WRITE;
  249.       freeioa->ioa_Request.io_Flags = ADIOF_PERVOL | IOF_QUICK;
  250.       freeioa->ioa_Request.io_Unit = unitno;
  251.  
  252.       freeioa->ioa_Period = period;
  253.       freeioa->ioa_Volume = 32;            /* between 0 and 64 */
  254.       freeioa->ioa_Data = waveform_ptr;
  255.       freeioa->ioa_Length = waveform_len;
  256.  
  257.       freeioa->ioa_Cycles = 0;
  258.  
  259. This assumes that we have already copied the OpenDevice info into it and
  260. have created a unique ReplyPort for it.  In our sample program, this would
  261. be an array.  CMD_WRITE is the command to set waveform and begin audio
  262. generation.  The flag ADIOD_PERVOL says to set period and volume as well.
  263. The flag IOF_QUICK is a flag telling to perform this as quickly as
  264. possible.  It is used here to make CMD_WRITE synchronous in case of an
  265. error.  The variable unitno is a bitmap for the channel(s) for which
  266. to play the tone.  (1 for channel 1, 2 for channel 2, 4 for channel 3, and
  267. 8 for channel 4, or any combination thereof.)  ioa_Cycles is the number of
  268. cycles which the tone will play for.  If set to zero, the tone will play
  269. continuously until aborted by AbortIO() or by an ADCMD_FINISH command.  The
  270. latter is recommended.
  271.  
  272.   Since we set ioa_Cycles to zero, we must consider the possibility that
  273. the audio channel we wish to use is already playing a tone.  A flag should
  274. be kept concerning this fact.  If a tone is already playing, we must stop
  275. it first, which requires an ADCMD_FINISH command to be issued.  The
  276. finishioa structure does not need a ReplyPort, as ADCMD_FINISH is
  277. synchronous.  This initialization, with the exception of the unitno,
  278. can be done once, with our main initialization, but is shown here for
  279. clarity.
  280.  
  281.    if (waiting[voice])
  282.       {
  283.       finishioa->ioa_Request.io_Command = ADCMD_FINISH;
  284.       finishioa->ioa_Request.io_Flags = IOF_QUICK;
  285.       finishioa->ioa_Request.io_Unit = unitno;
  286.       BeginIO(finishioa);
  287.       WaitIO(ioainuse);
  288.       waiting[voice] = NO;
  289.       }
  290.  
  291. ioainuse is the IOAudio structure which was used for the previous
  292. CMD_WRITE on this channel.  After it has been told to finish, it sends a
  293. message that it has done so to the ReplyPort specified in it.  WaitIO()
  294. waits until this message has been received, and then continues.
  295.  
  296.   Finally we can start our tone.  This is simply done, by:
  297.  
  298.    BeginIO(freeioa);
  299.    error = CheckIO(freeioa);
  300.    if (error)
  301.       <do error recovery>
  302.    else
  303.       waiting[voice] = YES;
  304.  
  305. In our sample program, we then swap the freeioa and ioainuse pointers, so
  306. that we can easily use the same code for the next tone.  All of this code
  307. is in setwpv() in SCALES.C for your perusal.
  308.  
  309. All that remains is a routine which will select the waveform to be used and
  310. the period, and this can be a table lookup.  To make things easier on the
  311. driver, however, we can make a simple routine which will just change the
  312. period if the waveform does not change.  This routine, which can also
  313. control the volume, can be used whenever the octave is the same, and can
  314. come in handy later should we desire envelope control or vibrato:
  315.  
  316.    ioapv->ioa_Request.io_Command = ADIOF_PERVOL;
  317.    ioapv->ioa_Request.io_Flags = IOF_QUICK;
  318.    ioapv->ioa_Request.io_Unit = unitno;
  319.  
  320.    ioapv->ioa_Period = period;
  321.    ioapv->ioa_Volume = 32;
  322.    BeginIO(ioapv);
  323.  
  324. Since ADCMD_PERVOL is synchronous, it requires no wait and no ReplyPort.
  325. This should only be used if a CMD_WRITE on the given unitno is in progress.
  326. If not, I have no idea as to the results.
  327.  
  328.   The waveform and period select routine, which also decides if it can
  329. use the ADCMD_PERVOL code, is called strike() in SCALES.C.  It also
  330. handles "rests" by shutting the volume down to zero.  For determining
  331. durations of notes, one can use the Delay() function, although for
  332. serious music generation, I would suggest the microhz timer instead.
  333.  
  334.  
  335. Cleaning up
  336. -------- --
  337.  
  338.   When your program ends, it is always important to free up the allocated
  339. memory, the ReplyPorts, and the device.  For simplicity, I am using the
  340. FinishProg() routine in SCALES.C.  If you don't do it, nobody will.
  341.  
  342.   If you are still confused, examine SCALES.C, where all this stuff is
  343. used in a working application.  All subroutines in there can be used by
  344. anyone who wants to.
  345.  
  346. Other applications
  347. ----- ------------
  348.  
  349.   There are many other uses for the audio routines.  Digitized sound could
  350. be used in place of a waveform for interesting effects, although the period
  351. would most likely require change.  Sound effects could be created by quickly
  352. changing period and waveform and volume.  Supposedly, one can link pairs of
  353. channels for modulation, but I have no idea as to how to do it.  And speech
  354. can be generated, but not with these routines.  Have fun!
  355.  
  356. S. A. Bennett
  357. 12/31/85
  358. ===End of Discussion===
  359.  
  360.  
  361.  
  362.